package com.robot.merchant.controller;

import com.alibaba.fastjson.JSON;
import com.robot.merchant.client.GoodsClient;
import com.robot.merchant.client.MemberClient;
import com.robot.merchant.client.OrdersClient;
import com.robot.merchant.client.SmsClient;
import com.robot.merchant.pojo.Store;
import com.robot.merchant.pojo.vo.StoreWithTags;
import com.robot.merchant.service.StoreService;
import com.robot.merchant.service.TagService;
import entity.*;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import util.*;
import util.qr.entity.NickName;
import util.qr.entity.QrCode;
import util.qr.handler.PosterUtil;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * store控制器层
 *
 * @author wuyunbin
 */
@RestController
@CrossOrigin
@RequestMapping("/store")
public class StoreController {
    @Autowired
    private StoreService storeService;
    @Autowired
    private TagService tagService;

    @Autowired
    private MemberClient memberClient;
    @Autowired
    private OrdersClient ordersClient;
    @Autowired
    private GoodsClient goodsClient;
    @Autowired
    private SmsClient smsClient;

    @Autowired
    private CheckUtil checkUtil;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private GaoDeMapUtil gaoDeMapUtil;

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private BCryptPasswordEncoder encoder;

    /**
     * store表status 0-禁用 1-启用
     */
    private final String storeStatusEnable = "1";

    @Autowired
    private RabbitTemplate rabbitTemplate;
    private final Logger logger = LoggerFactory.getLogger(this.getClass());


    /**
     * 修改密码
     *
     * @param store
     * @param checkCode
     * @return
     */
    @PutMapping("updatePassword/{checkCode}")
    @Transactional(rollbackFor = Exception.class)
    public Result updatePassword(@PathVariable String checkCode, @RequestBody Store store) {
        Claims claims = (Claims) request.getAttribute("robot_merchant");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对商家是否存在和状态进行判断

        Store storeInDb = storeService.findById(claims.getId());
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        String phone = store.getPhone();
        checkCode = checkCode.trim();
        if ("".equals(checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }
        //验证码是不是过期
        Sms sms = new Sms("merchant", phone, "updatePassword");

        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        if (store.getPassword() != null && !"".equals(store.getPassword())) {
            storeInDb.setPassword(encoder.encode(store.getPassword()));
        } else {
            return new Result(StatusCode.ERROR_PASSWORD_REQUIRED);
        }
        storeInDb.setUpdatedAt(LocalDateTime.now());
        storeService.update(storeInDb);
        smsClient.deleteCheckCode(sms);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }

    /**
     * 找回密码
     *
     * @param store
     * @param checkCode
     * @return
     */
    @RequestMapping(value = "findPassword/{checkCode}", method = RequestMethod.PUT)
    @Transactional(rollbackFor = Exception.class)
    public Result findPassword(@PathVariable String checkCode, @RequestBody Store store) {
        String phone = store.getPhone();
        if (store.getPhone() == null || "".equals(store.getPhone())) {
            return new Result(StatusCode.ERROR_PHONE_REQUIRED);
        } else if (!checkUtil.checkPhone(store.getPhone())) {
            return new Result(StatusCode.ERROR_INVALID_PHONE);
        }
        checkCode = checkCode.trim();
        if ("".equals(checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }
        //验证码是不是过期
        Sms sms = new Sms("merchant", phone, "findPassword");

        if (!smsClient.isCheckCodeExpire(sms)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE_EXPIRED);
        }
        //验证码是否正确
        if (!smsClient.isCorrectCheckCode(sms, checkCode)) {
            return new Result(StatusCode.ERROR_VERIFICATION_CODE);
        }

        Store storeInDb = storeService.findByPhone(store.getPhone());
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        if (store.getPassword() != null && !"".equals(store.getPassword())) {
            storeInDb.setPassword(encoder.encode(store.getPassword()));
        } else {
            return new Result(StatusCode.ERROR_PASSWORD_REQUIRED);
        }
        storeInDb.setUpdatedAt(LocalDateTime.now());
        storeService.update(storeInDb);
        smsClient.deleteCheckCode(sms);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }

    /**
     * 店铺/商家信息
     *
     * @return
     */
    @RequestMapping(value = "/findByToken", method = RequestMethod.GET)
    public Result findByToken() {
        Claims claims = (Claims) request.getAttribute("robot_merchant");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        Store storeInDb = storeService.findById(claims.getId());
        if (storeInDb == null || storeInDb.getDeletedAt() != null) {
            return new Result(StatusCode.ERROR_USER_DOES_NOTE_EXIST);
        }
        if (!storeStatusEnable.equals(storeInDb.getStatus())) {
            return new Result(StatusCode.ERROR_USER_INVALID);
        }
        return new Result(StatusCode.SUCCESS_QUERY, storeInDb);
    }

    /**
     * 查询全部数据
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.GET)
    public Result findAll() {
        return new Result(StatusCode.SUCCESS_QUERY, storeService.findAll());
    }

    /**
     * 店铺详情-聚合
     *
     * @param id
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "/{id}/{page}/{size}", method = RequestMethod.POST)
    public Result findById(@RequestBody Map searchMap, @PathVariable String id, @PathVariable int page, @PathVariable int size) {
        Store storeInDb = storeService.findById(id);
        if (storeInDb == null) {
            return new Result(StatusCode.ERROR_STORE_DOES_NOTE_EXIST);
        }
        if (!storeStatusEnable.equals(storeInDb.getStatus())) {
            return new Result(StatusCode.ERROR_MERCHANT_DISABLED);
        }
        HashMap<String, Object> map = new HashMap<>(5);
        map.put("store", storeInDb);
        map.put("tags", tagService.findTagsByStoreId(id));
        map.put("evaluates", JSON.parseObject(memberClient.thirdFindEvaluatesByStoreId(id, page, size)));
        map.put("goodsCategory", JSON.parseObject(goodsClient.thirdFindGoodsCategoryBySearch(new HashMap(1), page, size)));
        map.put("goods", JSON.parseObject(goodsClient.thirdFindGoodsBySearch(searchMap, page, size)));
        return new Result(StatusCode.SUCCESS_QUERY, map);
    }

    /**
     * 店铺详情-店铺和标签
     *
     * @param id
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "store/{id}/{page}/{size}", method = RequestMethod.GET)
    public Result findStoreById(@PathVariable String id, @PathVariable int page, @PathVariable int size) {
        Store storeInDb = storeService.findById(id);
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        HashMap<String, Object> map = new HashMap<>(5);
        map.put("store", storeInDb);
        map.put("tags", tagService.findTagsByStoreId(id));
        return new Result(StatusCode.SUCCESS_QUERY, map);
    }

    /**
     * 店铺详情-评论
     *
     * @param id
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "storeEvaluates/{id}/{page}/{size}", method = RequestMethod.GET)
    public Result findStoreEvaluatesById(@PathVariable String id, @PathVariable int page, @PathVariable int size) {
        Store storeInDb = storeService.findById(id);
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        return new Result(StatusCode.SUCCESS_QUERY, JSON.parseObject(memberClient.thirdFindEvaluatesByStoreId(id, page, size)));
    }

    /**
     * 店铺详情-商品分类列表并分页
     *
     * @param id
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "storeGoodsCategory/{id}/{page}/{size}", method = RequestMethod.GET)
    public Result findStoreGoodsCategoryById(@PathVariable String id, @PathVariable int page, @PathVariable int size) {
        Store storeInDb = storeService.findById(id);
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        return new Result(StatusCode.SUCCESS_QUERY, JSON.parseObject(goodsClient.thirdFindGoodsCategoryBySearch(new HashMap(1), page, size)));
    }

    /**
     * 店铺详情-商品分类列表
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "storeGoodsCategory/{id}", method = RequestMethod.GET)
    public Result findStoreGoodsCategoryById(@PathVariable String id) {
        Store storeInDb = storeService.findById(id);
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        return new Result(StatusCode.SUCCESS_QUERY, JSON.parse(goodsClient.thirdFindGoodsCategory()));
    }

    /**
     * 店铺详情-商品列表
     *
     * @param id
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "storeGoods/{id}/{page}/{size}", method = RequestMethod.POST)
    public Result findStoreGoodsCategoryById(@RequestBody Map<String, String> searchMap, @PathVariable String id, @PathVariable int page, @PathVariable int size) {
        Store storeInDb = storeService.findById(id);
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        searchMap.put("storeId", storeInDb.getId());
        return new Result(StatusCode.SUCCESS_QUERY, JSON.parseObject(goodsClient.thirdFindGoodsBySearch(searchMap, page, size)));
    }

    /**
     * 店铺详情-店铺信息
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Result findById(@PathVariable String id) {
        Store storeInDb = storeService.findById(id);
        String message = storeService.checkStore(storeInDb);
        if (!"".equals(message)) {
            return new Result(StatusCode.ERROR, message);
        }

        return new Result(StatusCode.SUCCESS_QUERY, storeInDb);
    }


    /**
     * 分页+多条件查询
     *
     * @param searchMap 查询条件封装
     * @param page      页码
     * @param size      页大小
     * @return 分页结果
     */
    @RequestMapping(value = "/search/{page}/{size}", method = RequestMethod.POST)
    public Result findSearch(@RequestBody Map searchMap, @PathVariable int page, @PathVariable int size) {
        Page<Store> pageList = storeService.findSearch(searchMap, page, size);
        return new Result(StatusCode.SUCCESS_QUERY, new PageResult<Store>(pageList.getTotalElements(), pageList.getContent()));
    }

    /**
     * 分页+多条件查询
     *
     * @param searchMap 查询条件封装
     * @param page      页码
     * @param size      页大小
     * @return 分页结果
     */
    @RequestMapping(value = "index/{page}/{size}", method = RequestMethod.POST)
    public Result findSearchToIndex(@RequestBody Map<String, String> searchMap, @PathVariable int page, @PathVariable int size) {
        searchMap.put("status", storeStatusEnable);
        Page<Store> pageList = storeService.findSearch(searchMap, page, size);
        logger.info(pageList.getContent().toString());
        List<StoreWithTags> storeWithTagsList = storeService.getStoriesWithTags(pageList.getContent());

        Map<String, Object> map = new HashMap<>(2);
        map.put("storeAndTagsList", storeWithTagsList);
        map.put("total", pageList.getTotalElements());
        logger.info(map.toString());
        return new Result(StatusCode.SUCCESS_QUERY, map);
    }

    /**
     * 附近的店铺
     *
     * @param point
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "getStoresByPoint/{page}/{size}", method = RequestMethod.POST)
    public Result getStoresByPoint(@RequestBody Point point, @PathVariable int page, @PathVariable int size) {
        logger.info(point.toString());
        GeoHashUtil geoHashUtil = new GeoHashUtil();
        String geoHash = geoHashUtil.encode(Double.parseDouble(point.getLatitude()), Double.parseDouble(point.getLongitude()));
        String halfGeoHash = geoHashUtil.halfGeoHash(Double.parseDouble(point.getLatitude()), Double.parseDouble(point.getLongitude()));
        logger.info(geoHash);
        logger.info(halfGeoHash);

        Page<Store> stores = storeService.findByPoint(point, page, size);

        logger.info(stores.getContent().toString());
        List<StoreWithTags> storeWithTagsList = storeService.getStoriesWithTags(stores.getContent());

        Map<String, Object> map = new HashMap<>(2);
        map.put("storeAndTagsList", storeWithTagsList);
        map.put("total", stores.getTotalElements());
        logger.info(map.toString());
        return new Result(StatusCode.SUCCESS_QUERY, map);
    }

    /**
     * 行业下的店铺列表
     *
     * @param industryId
     * @return
     */
    @RequestMapping(value = "getStoriesListByIndustryId/{industryId}", method = RequestMethod.GET)
    public Result getStoriesListByIndustryId(@PathVariable String industryId) {
        List<Store> stories = storeService.getStoriesByIndustryId(industryId);
        return new Result(StatusCode.SUCCESS_QUERY, stories);
    }

    /**
     * 行业下的店铺列表并分页
     *
     * @param point
     * @param industryId
     * @param page
     * @param size
     * @return
     */
    @RequestMapping(value = "getStoriesPageByIndustryId/{industryId}/{page}/{size}", method = RequestMethod.POST)
    public Result getStoriesListByIndustryId(@RequestBody Point point, @PathVariable String industryId, @PathVariable int page, @PathVariable int size) {
        logger.info(point.toString());
        Page<Store> stories = storeService.findByPointAndIndustryId(point,industryId,page,size);
        List<StoreWithTags> storeWithTagsList=storeService.getStoriesWithTags(stories.getContent());
        Map<String, Object> map = new HashMap<>(2);
        map.put("storeAndTagsList", storeWithTagsList);
        map.put("total", stories.getTotalElements());
        logger.info(map.toString());
        return new Result(StatusCode.SUCCESS_QUERY, map);
    }


    /**
     * 根据条件查询
     *
     * @param searchMap
     * @return
     */
    @RequestMapping(value = "/search", method = RequestMethod.POST)
    public Result findSearch(@RequestBody Map searchMap) {
        return new Result(StatusCode.SUCCESS_QUERY, storeService.findSearch(searchMap));
    }

    /**
     * 商家修改资料
     *
     * @param store
     */
    @RequestMapping(value = "", method = RequestMethod.PUT)
    public Result update(@RequestBody Store store) {
        logger.info("store=" + store);
        Claims claims = (Claims) request.getAttribute("robot_merchant");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对商家是否存在和状态进行判断

        Store storeInDb = storeService.findById(claims.getId());
        logger.info("before update storeInDb=" + storeInDb);

        if (store.getPhone() != null && !"".equals(store.getPhone())) {
            if (!checkUtil.checkPhone(store.getPhone())) {
                return new Result(StatusCode.ERROR_INVALID_PHONE);
            }
        }
        if (store.getEmail() != null && !"".equals(store.getEmail())) {
            if (checkUtil.checkEmail(store.getEmail())) {
                return new Result(StatusCode.ERROR_INVALID_EMAIL);
            }
        }
        if (store.getLongitude() != null && !"".equals(store.getLongitude()) && store.getLatitude() != null && !"".equals(store.getLatitude())) {
            GeoHashUtil geoHashUtil = new GeoHashUtil();
            String geoHash = geoHashUtil.encode(Double.parseDouble(store.getLatitude()), Double.parseDouble(store.getLongitude()));
            String halfGeoHash = geoHashUtil.halfGeoHash(Double.parseDouble(store.getLatitude()), Double.parseDouble(store.getLongitude()));
            logger.info("geoHash=" + geoHash);
            logger.info("halfGeoHash=" + halfGeoHash);
            store.setGeoHash(geoHash);
            store.setHalfGeoHash(halfGeoHash);
        }
        store.setId(storeInDb.getId());
        store.setRealNameStatus(storeInDb.getRealNameStatus());
        store.setStatus(storeInDb.getStatus());
        store.setPassword(storeInDb.getPassword());
        UpdateUtil.copyNonNullProperties(store, storeInDb);
        logger.info("after update storeInDb=" + storeInDb);
        storeService.update(storeInDb);
        return new Result(StatusCode.SUCCESS_UPDATED);
    }


    /**
     * 订单列表
     *
     * @param searchMap 查询条件封装
     * @param page      页码
     * @param size      页大小
     * @return 分页结果
     */
    @PostMapping("/searchOrders/{page}/{size}")
    public Result searchOrders(@RequestBody Map searchMap, @PathVariable int page, @PathVariable int size) {
        Claims claims = (Claims) request.getAttribute("robot_merchant");
        if (claims == null) {
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        //前端调用findByToken接口检查过了,所以这里不再对商家是否存在和状态进行判断

        return new Result(StatusCode.SUCCESS_QUERY, JSON.parseObject(ordersClient.thirdFindSubOrdersByStoreId(claims.getId(), page, size)));
    }

    /**
     * 用户搜索店铺列表并分页
     *
     * @param searchMap 查询条件封装
     * @param page      页码
     * @param size      页大小
     * @return 分页结果
     */
    @PostMapping("/searchStores/{page}/{size}")
    public Result searchStores(@RequestBody Map<String, String> searchMap, @PathVariable int page, @PathVariable int size) {
        //先判断关键词是否为空
        String keywords = searchMap.get("keywords");
        if("".equals(keywords)){
            return new Result(StatusCode.ERROR_KEYWORDS_REQUIRED);
        }
        HashMap<String, String> logsMap = new HashMap<>(2);
        logsMap.put("keywords", keywords);
        logsMap.put("type", "search");
        rabbitTemplate.convertAndSend("logs", logsMap);
        
        Claims claims = (Claims) request.getAttribute("robot_member");
        if (claims != null) {
            logsMap.put("memberId", claims.getId());
        }

        String longitude = searchMap.get("longitude");
        String latitude = searchMap.get("latitude");
        logger.info("longitude=" + longitude + ", latitude=" + latitude);

        Point point=null;
        //如果有带坐标
        if(!"".equals(longitude)&&!"".equals(latitude)){
            point = new Point(latitude, longitude);
        }
        Page<Store>  pageList = storeService.findStoresByKeywordsAndStatusAndDeletedAtIsNull(point, keywords, page, size);
        searchMap.put("status", storeStatusEnable);
        searchMap.put("storeName", keywords);
        searchMap.put("recommendation", keywords);

        List<StoreWithTags> storeWithTagsList = storeService.getStoriesWithTags(pageList.getContent());

        Map<String, Object> map = new HashMap<String, Object>(2);
        map.put("storeAndTagsList", storeWithTagsList);
        map.put("total", pageList.getTotalElements());
        return new Result(StatusCode.SUCCESS_QUERY, map);
    }

    @RequestMapping(value = "/createScanCode",method = RequestMethod.GET)
    public Result createScanCode(){
        Claims claims=(Claims)request.getAttribute("robot_merchant");
        if(claims==null){
            return new Result(StatusCode.ERROR_TOKEN_EXPIRED);
        }
        logger.info("claims.getId()=" + claims.getId());
        Store store=storeService.findById(claims.getId());

        PosterUtil posterUtil=new PosterUtil();

        String backgroundImage="https://mashangjie-prod.oss-cn-qingdao.aliyuncs.com/scan_code_background.jpg";
        //构建店名对象放到昵称里面
        NickName nickName=new NickName(store.getStoreName(),45,88,5);

        logger.info("nickName\n"+nickName.toString());

        //构建二维码对象
        String qrText="http://member.mashangjie.shop/#/pages/offlinepay/offlinepay?storeId="+store.getId();
        QrCode qrCode=new QrCode(qrText,50,50,25,50);
        logger.info(qrCode.toString());
        HashMap<String,String> result=new HashMap<>();
        result.put("base64",posterUtil.posterCreate(backgroundImage,nickName,null,qrCode));

        return new Result(StatusCode.SUCCESS,result);
    }
}
